#include <iostream>
#include <sstream>
#include "unistd.h"
#include "string"
#include "windows.h"

#include "exception/FileNonExistException.h"
#include "exception/FileNonReadException.h"
#include "exception/RequiredParameterMissingException.h"
#include "exception/IllegalParameterException.h"
#include "exception/DuplicatedParameterException.h"
#include "exception/ConflictParameterException.h"
#include "exception/ParameterTypeException.h"
#include "exception/FileContentException.h"
#include "exception/FileEmptyException.h"
#include "exception/NonMatchedChainException.h"
#include "exception/CircleTypeException.h"
#include "exception/DuplicatedWordException.h"
#include "exception/OneLetterWordException.h"
#include "exception/WordsOverflowException.h"
#include "exception/ResultOverflowException.h"

using namespace std;

//cmd: max_length_chain.exe -n absolute_path_of_word_list
string solution(FILE* file, int type, char head_letter, char tail_letter, char head_not_letter, bool is_circle);

string char_p_2_string(char* p);
string solution_for_cmd(int argc, char* argv[]);
string catch_exception(int argc, char* argv[]);

string output;
bool print_answer_and_exception = true;

// 输出格式仅供测试
int main(int argc, char* argv[]) {
    SetConsoleOutputCP(CP_UTF8);

    catch_exception(argc, argv);

    return 0;
}

string catch_exception(int argc, char* argv[]) {
    try {
        output = solution_for_cmd(argc, argv);
    }
    catch (FileNonExistException &e) {
        output = e.print_exception();
    }
    catch (FileNonReadException &e) {
        output = e.print_exception();
    }
    catch (RequiredParameterMissingException &e) {
        output = e.print_exception();
    }
    catch (IllegalParameterException &e) {
        output = e.print_exception();
    }
    catch (DuplicatedParameterException &e) {
        output = e.print_exception();
    }
    catch (ConflictParameterException &e) {
        output = e.print_exception();
    }
    catch (ParameterTypeException &e) {
        output = e.print_exception();
    }
    catch (FileContentException &e) {
        output = e.print_exception();
    }
    catch (FileEmptyException &e) {
        output = e.print_exception();
    }
    catch (CircleTypeException &e) {
        output = e.print_exception();
    }
    catch (NonMatchedChainException &e) {
        output = e.print_exception();
    }
    catch (DuplicatedWordException &e) {
        output = e.print_exception();
    }
    catch (OneLetterWordException &e) {
        output = e.print_exception();
    }
    catch (WordsOverflowException &e) {
        output = e.print_exception();
    }
    catch (ResultOverflowException &e) {
        output = e.print_exception();
    }

    if (print_answer_and_exception) {
        cout << output;
    }

    return output;
}

string solution_for_cmd(int argc, char* argv[]) {
    int type;
    char head_letter = 0, tail_letter = 0, head_not_letter = 0;
    bool is_circle = false;

    if (argc < 3) {
        throw RequiredParameterMissingException();
    }

//    char* exe_file = argv[0];

    string words_file = char_p_2_string(argv[argc - 1]);
//    words_file = words_file.append(".txt");

    if (access(words_file.data(), F_OK) == -1) {
        throw FileNonExistException(words_file);
    }
    else if (access(words_file.data(), R_OK) == -1) {
        throw FileNonReadException(words_file);
    }

    int param_n = 0, param_w = 0, param_c = 0, param_h = 0, param_t = 0, param_j = 0, param_r = 0;
    string char_h, char_t, char_j;

    for (int i = 1;i < argc - 1;i++) {
        string param = char_p_2_string(argv[i]);

        if (param == "-n") {
            param_n++;
        }
        else if (param == "-w") {
            param_w++;
        }
        else if (param == "-c") {
            param_c++;
        }
        else if (param == "-h") {
            param_h++;
            i++;
            char_h = char_p_2_string(argv[i]);

            if (!isalpha(char_h.at(0))) {
                throw RequiredParameterMissingException("-h");
            }

        }
        else if (param == "-t") {
            param_t++;
            i++;
            char_t = char_p_2_string(argv[i]);

            if (!isalpha(char_t.at(0))) {
                throw RequiredParameterMissingException("-t");
            }
        }
        else if (param == "-j") {
            param_j++;
            i++;
            char_j = char_p_2_string(argv[i]);

            if (!isalpha(char_j.at(0))) {
                throw RequiredParameterMissingException("-j");
            }
        }
        else if (param == "-r") {
            param_r++;
        }
        else {
            throw IllegalParameterException();
        }
    }

    if (param_n > 1 || param_w > 1 || param_c > 1 || param_h > 1 || param_t > 1 || param_j > 1 || param_r > 1) {
        throw DuplicatedParameterException();
    }

    if (param_n + param_w + param_c == 0) {
        throw RequiredParameterMissingException();
    }
    else if (param_n + param_w + param_c != 1) {
        throw ConflictParameterException();
    }
    else {
        if (param_n == 1) {
            type = 0;
        }
        else if (param_w == 1) {
            type = 1;
        }
        else {
            type = 2;
        }
    }

    if (param_h == 1) {
        if (char_h.size() == 1) {
            head_letter = char_h.at(0);
        }
        else {
            throw ParameterTypeException("-h");
        }
    }
    if (param_t == 1) {
        if (char_t.size() == 1) {
            tail_letter = char_t.at(0);
        }
        else {
            throw ParameterTypeException("-t");
        }
    }
    if (param_j == 1) {
        if (char_j.size() == 1) {
            head_not_letter = char_j.at(0);
        }
        else {
            throw ParameterTypeException("-j");
        }
    }

    if (param_r == 1) {
        is_circle = true;
    }

    FILE* file = fopen(words_file.data(), "r");

    string out = solution(file, type, head_letter, tail_letter, head_not_letter, is_circle);
    fclose(file);

    return out;
}

string char_p_2_string(char* p) {
    stringstream ss;

    ss << p;
    string s;
    ss >> s;

    return s;
}
